package com.token.iot.bratterycharging.gateway.business.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.jms.ObjectMessage;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.outstanding.framework.base.OutstandingService;
import com.outstanding.framework.base.mq.MQProducer;
import com.outstanding.framework.core.Logger;
import com.outstanding.framework.core.PendingException;
import com.outstanding.framework.core.TransactionContext;
import com.outstanding.framework.log.LoggerFactory;
import com.outstanding.framework.utils.NetUtils;
import com.token.iot.bratterycharging.gateway.ChannelHandlerContextManager;
import com.token.iot.bratterycharging.gateway.Code;
import com.token.iot.bratterycharging.gateway.CodeType;
import com.token.iot.bratterycharging.gateway.ResCode;
import com.token.iot.bratterycharging.gateway.Semaphore;
import com.token.iot.bratterycharging.gateway.SemaphoreManager;
import com.token.iot.bratterycharging.gateway.Sender;
import com.token.iot.bratterycharging.gateway.SenderFactory;
import com.token.iot.bratterycharging.gateway.api.Constant;
import com.token.iot.bratterycharging.gateway.api.ConsumptionAmount;
import com.token.iot.bratterycharging.gateway.api.DeviceParam;
import com.token.iot.bratterycharging.gateway.api.DeviceState;
import com.token.iot.bratterycharging.gateway.api.Fee;
import com.token.iot.bratterycharging.gateway.api.Port;
import com.token.iot.bratterycharging.gateway.api.PortState;
import com.token.iot.bratterycharging.gateway.api.PowersFee;
import com.token.iot.bratterycharging.gateway.business.DuplexProcessor;
import com.token.iot.bratterycharging.gateway.business.DuplexProcessorFactory;
import com.token.iot.bratterycharging.gateway.dao.CodeHistoryDAO;
import com.token.iot.bratterycharging.gateway.dao.ExceptionDAO;
import com.token.iot.bratterycharging.gateway.server.SenderService;
import com.token.iot.bratterycharging.gateway.utils.ChannelHandlerContextUtil;

import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class BratteryChargingService extends OutstandingService {

	@Autowired
	private CodeHistoryDAO dao;

	@Autowired
	private MQProducer mQProducer;

	@Autowired
	private ExceptionDAO exceptionDao;

	

	protected static ChannelHandlerContextManager manager = new ChannelHandlerContextManager();

	protected static Logger loger = LoggerFactory.getLogger("transactionLogger");

	static public final AttributeKey<Long> attributeTIME = AttributeKey.valueOf("TIME");

	/**
	 * 异步转同步的操作
	 * 
	 * @param processor
	 * @param imei
	 * @param params
	 * @return
	 * @throws PendingException
	 */
	private Object call(DuplexProcessor processor, String imei, Map<String, String> params) throws PendingException {
		// 查找对应的HandlerContext
		ChannelHandlerContext context = manager.getChannelHandlerContextByImei(imei);
		processor.setContext(context);

		// 锁住context
		synchronized (context) {
			Attribute<Long> attr = context.channel().attr(attributeTIME);
			Long time = null;
			time = attr.get();
			if(time != null) {
				if (System.currentTimeMillis() < time + 2 * 1000) {
					try {
						Thread.sleep(1500);
					} catch (InterruptedException e) {
						loger.error(e);
					}
				}
			}

			attr.set(System.currentTimeMillis());
		}

		// 发送指令
		String sessiondid = (String) processor.send(imei, params);
		String key = imei + "@" + sessiondid;
		// loger.info(" the " + this.getClass() + " key =" + key);
		// 信号量
		Semaphore semaphore = SemaphoreManager.registerCommand(key, processor);
		//记录指令发送日志
		try {
			Code code = new Code();
			if (imei != null) {
				// 查找对应的HandlerContext
				String ip = "";
				if (context != null) {
					ip = ChannelHandlerContextUtil.getIP(context);
				}
				code.setIp(ip);
			}
			code.setCode(processor.getCode());
			code.setCodeType(CodeType.Send);
			Gson gson = new Gson();

			String strParams = gson.toJson(params);
			code.setParams(strParams);
			code.setImei(imei);

			String serverIp = NetUtils.getLocalIP();
			code.setServerIp(serverIp);
			code.setDeviceType(Constant.DEVICETYPE);
			String sessionId = (String) TransactionContext.getData(Constant.SESSIONID);
			code.setSessionId(sessionId);
			dao.insert(code);
		} catch (Exception e) {
			loger.error(e);
			try {
				Throwable t = e.getCause();
				String contextStr = e.getMessage();
				if (t != null) {
					contextStr = " case:" + t.getMessage();
				}
				exceptionDao.insertImei(contextStr, imei);
			} catch (Exception ee) {
				loger.error("exceptionDao read has exception", ee);
			}
			throw new PendingException(ResCode.CALLERROR, e);

		}
		try {
			semaphore.await();
		} catch (Exception e) {
			loger.error(e);
			try {
				Throwable t = e.getCause();
				String contextStr = e.getMessage();
				if (t != null) {
					contextStr = " case:" + t.getMessage();
				}
				exceptionDao.insertImei(contextStr, imei);
			} catch (Exception ee) {
				loger.error("exceptionDao read has exception", ee);
			}
			throw new PendingException(ResCode.semaphoreTimeOut,e);
		}
		String response = null;
		try {
			
			// 得到回复
			response = semaphore.getResponse();
			// loger.info("The " + this.getClass() + " Semaphore =" + response);
			return processor.response(response);
		} catch (Exception e) {
			loger.error(e);
			try {
				Throwable t = e.getCause();
				String contextStr = e.getMessage();
				if (t != null) {
					contextStr = " case:" + t.getMessage();
				}
				exceptionDao.insertImei(contextStr, imei);
			} catch (Exception ee) {
				loger.error("exceptionDao read has exception", ee);
			}
			throw new PendingException(ResCode.CALLERROR, e);

		}finally {
			//记录响应日志
			try {
				String ip = ChannelHandlerContextUtil.getIP(context);
				Code code = new Code();
				code.setCode(processor.getCode());
				code.setCodeType(CodeType.Oper);
				code.setParams(response);
				code.setImei(imei);
				code.setIp(ip);
				String serverIp = NetUtils.getLocalIP();
				code.setServerIp(serverIp);
				code.setDeviceType(Constant.DEVICETYPE);
				String sessionId = (String) TransactionContext.getData(Constant.SESSIONID);
				code.setSessionId(sessionId);
				dao.insert(code);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
	}

	/**
	 * 远程开关机
	 * 
	 * @param imei
	 * @param flag
	 *            true开机，false关机
	 * @return
	 * @throws PendingException
	 */
	public boolean remotePower(String imei, boolean flag) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DKB");
		HashMap<String, String> map = new HashMap<String, String>();
		map.put(Constant.FLAG, String.valueOf(flag));
		Boolean power = (Boolean) call(sender, imei, map);
		return power;

	}

	/**
	 * 
	 * @param imei
	 * @param index
	 * @param fenzhong
	 * @return 1 为成功
	 * @throws PendingException
	 */
	// 设备开始充电
	public int charge(String imei, int index, int fenzhong) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("RUN");
		HashMap<String, String> map = new HashMap();
		if (index > 10 || index < 1) {
			throw new PendingException(ResCode.PORTOUTOFBOUDS);
		}
		map.put(Constant.PORT, String.valueOf(index));
		map.put(Constant.TIME, String.valueOf(fenzhong));
		int power = (Integer) call(sender, imei, map);
		return power;
	}

	

	/**
	 * 设备所有端口查询
	 * 
	 * @param imei
	 * @throws PendingException
	 */
	public List<Port> getPortInfo(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("STA");
		return (List<Port>) call(sender, imei, null);

	}

	/**
	 * 获取功能掩码
	 * 
	 * @param imei
	 * @return
	 * @throws PendingException
	 */
	public String getMainboard(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("GYM");
		return (String) call(sender, imei, null);
	}

	/**
	 * 设备参数设置
	 * 
	 * @param imei
	 * @param money
	 *            (单位为角)
	 * @param first
	 *            ,累加数 (单位分钟)
	 * @param second，累加数
	 *            (单位分钟)
	 * @param third，累加数
	 *            (单位分钟)
	 * @return
	 * @throws PendingException
	 */
	public Boolean setDeviceParams(String imei, int money, int first, int second, int third) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DCC");
		HashMap<String, String> map = new HashMap();
		map.put(Constant.MONEY, String.format("%03d", money));
		map.put(Constant.FIRST, String.format("%03d", first));
		map.put(Constant.SECOND, String.format("%03d", second));
		map.put(Constant.THIRD, String.format("%03d", third));
		return (Boolean) call(sender, imei, map);
	}

	/**
	 * 获取设备参数
	 * 
	 * @param imei
	 * @return
	 * @throws PendingException
	 */
	public DeviceParam getDeviceParams(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DCN");
		return (DeviceParam) call(sender, imei, null);
	}

	/**
	 * 设置5档功率和计费率
	 */
	public Boolean setPowerRatio(String imei, PowersFee pf) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("CHM");
		if ((pf.getPower1() >= pf.getPower2()) || (pf.getPower2() >= pf.getPower3())
				|| (pf.getPower3() >= pf.getPower4()) || (pf.getPower4() >= pf.getPower5())) {
			throw new PendingException(ResCode.POWERERROR);
		}
		HashMap<String, String> map = new HashMap();
		map.put(Constant.POWER1, String.format("%05d", pf.getPower1()));
		map.put(Constant.RATIO1, String.format("%03d", pf.getRatio1()));
		map.put(Constant.POWER2, String.format("%05d", pf.getPower2()));
		map.put(Constant.RATIO2, String.format("%03d", pf.getRatio2()));
		map.put(Constant.POWER3, String.format("%05d", pf.getPower3()));
		map.put(Constant.RATIO3, String.format("%03d", pf.getRatio3()));
		map.put(Constant.POWER4, String.format("%05d", pf.getPower4()));
		map.put(Constant.RATIO4, String.format("%03d", pf.getRatio4()));
		map.put(Constant.POWER5, String.format("%05d", pf.getPower5()));
		map.put(Constant.RATIO5, String.format("%03d", pf.getRatio5()));
		return (Boolean) call(sender, imei, map);
	}

	/**
	 * 设置设备IC卡和投币器是否可用
	 * 
	 * @param imei
	 * @param index
	 * @param flag
	 * @return
	 * @throws PendingException
	 */
	public Boolean setDevicePartEnable(String imei, boolean cardFlag, boolean coinFlag) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DCD");
		HashMap<String, String> map = new HashMap();
		map.put(Constant.CARD, String.valueOf(cardFlag));
		map.put(Constant.COIN, String.valueOf(coinFlag));
		return (Boolean) call(sender, imei, map);
	}

	/**
	 * 设置端口锁定或解锁
	 * 
	 * @param imei
	 * @param index
	 * @param flag
	 *            true:可用，false：锁定
	 * @return
	 * @throws PendingException
	 */
	public Boolean setDevicePort(String imei, int index, boolean flag) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DCG");
		HashMap<String, String> map = new HashMap();
		if (index > 10 || index < 1) {
			throw new PendingException(ResCode.PORTOUTOFBOUDS);
		}
		map.put(Constant.PORT, String.valueOf(index));
		map.put(Constant.FLAG, String.valueOf(flag));
		return (Boolean) call(sender, imei, map);
	}

	/**
	 * 停止充电
	 * 
	 * @param imei
	 * @param index
	 * @return
	 * @throws PendingException
	 */
	public Port stopCharge(String imei, int index) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("RTN");
		if (index > 10 || index < 1) {
			throw new PendingException(ResCode.PORTOUTOFBOUDS);
		}
		HashMap<String, String> map = new HashMap();
		map.put(Constant.PORT, String.valueOf(index));
		return (Port) call(sender, imei, map);
	}

	/**
	 * 查询设备端口的充电状态
	 * 
	 * @param imei
	 * @param index
	 * @return
	 * @throws PendingException
	 */
	public Port getPortChargeState(String imei, int index) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DCA");
		if (index > 10 || index < 1) {
			throw new PendingException(ResCode.PORTOUTOFBOUDS);
		}
		HashMap<String, String> map = new HashMap();
		map.put(Constant.PORT, String.valueOf(index));
		Port p = (Port) call(sender, imei, map);
		debug("the port =" + String.valueOf(p == null));
		p.setImei(imei);
		p.setStartTime(new Date());
		p.setState(PortState.FAULT);
		// 判断状态
		try {
			if (Integer.parseInt(p.getPower()) > 20) {
				p.setState(PortState.USEING);
			} else {
				p.setState(PortState.FREE);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return p;
	}

	/**
	 * 获取整机的充电状态
	 * 
	 * @param imei
	 * @return
	 * @throws PendingException
	 */
	public DeviceState getDeviceChargeState(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("CQZ");
		return (DeviceState) call(sender, imei, null);
	}

	/**
	 * 获取设备的消费总额
	 * 
	 * @param imei
	 * @return
	 * @throws PendingException
	 */
	public ConsumptionAmount getConsumptionAmount(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("DCB");
		return (ConsumptionAmount) call(sender, imei, null);
	}

	/**
	 * 设置充满后的策略
	 * 
	 * @param imei
	 * @param autoFlag
	 *            充满自停标志 :true 为自停，false为不自停
	 * @param cardFlag
	 *            刷卡退费标志：true 为退费，false为不退费
	 * @return
	 * @throws PendingException
	 */
	public Boolean setChargedPolicy(String imei, boolean autoFlag, boolean cardFlag) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("CHI");
		HashMap<String, String> map = new HashMap();
		map.put(Constant.CARD, String.valueOf(cardFlag));
		map.put(Constant.FLAG, String.valueOf(autoFlag));
		return (Boolean) call(sender, imei, map);
	}

	/**
	 * 读取设备5档功率和费率
	 * 
	 * @param imei
	 * @return
	 * @throws PendingException
	 */
	public PowersFee getPowerRatio(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("CHO");
		return (PowersFee) call(sender, imei, null);
	}

	/**
	 * 获取硬件版本号
	 * 
	 */
	public String getDeviceVersion(String imei) throws PendingException {
		DuplexProcessor sender = DuplexProcessorFactory.createDuplexProcessor("QBB");
		return (String) call(sender, imei, null);
	}

}
